{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://course.rs/basic/comment.html\n",
    "- https://practice-zh.course.rs/comments-docs.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 注释的种类\n",
    "\n",
    "在 Rust 中，注释分为三类：\n",
    "\n",
    "- 代码注释，用于说明某一块代码的功能，读者往往是同一个项目的协作开发者\n",
    "- 文档注释，支持 `Markdown`，对项目描述、公共 API 等用户关心的功能进行介绍，同时还能提供示例代码，目标读者往往是想要了解你项目的人\n",
    "- 包和模块注释，严格来说这也是文档注释中的一种，它主要用于说明当前包和模块的功能，方便用户迅速了解一个项目\n",
    "\n",
    "通过这些注释，实现了 Rust 极其优秀的文档化支持，甚至你还能在文档注释中写测试用例，省去了单独写测试用例的环节，我直呼好家伙！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# [代码注释](https://course.rs/basic/comment.html#代码注释)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "// 行注释 //\n",
    "\n",
    "fn main() {\n",
    "    // 我是Sun...\n",
    "    // face\n",
    "    let name = \"sunface\";\n",
    "    let age = 18; // 今年好像是18岁\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "// 块注释/* ..... */\n",
    "\n",
    "fn main() {\n",
    "    /*\n",
    "        我\n",
    "        是\n",
    "        S\n",
    "        u\n",
    "        n\n",
    "        ... 哎，好长!\n",
    "    */\n",
    "    let name = \"sunface\";\n",
    "    let age = \"???\"; // 今年其实。。。挺大了\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 文档注释"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当查看一个 `crates.io` 上的包时，往往需要通过它提供的文档来浏览相关的功能特性、使用方式，这种文档就是通过文档注释实现的。\n",
    "\n",
    "Rust 提供了 `cargo doc` 的命令，可以用于把这些文档注释转换成 `HTML` 网页文件，最终展示给用户浏览，这样用户就知道这个包是做什么的以及该如何使用。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 文档行注释 ///"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "/// `add_one` 将指定值加1\n",
    "///\n",
    "/// # Examples\n",
    "///\n",
    "/// ```\n",
    "/// let arg = 5;\n",
    "/// let answer = my_crate::add_one(arg);\n",
    "///\n",
    "/// assert_eq!(6, answer);\n",
    "/// ```\n",
    "pub fn add_one(x: i32) -> i32 {\n",
    "    x + 1\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以上代码有几点需要注意：\n",
    "\n",
    "- 文档注释需要位于 `lib` 类型的包中，例如 `src/lib.rs` 中\n",
    "- 文档注释可以使用 `markdown`语法！例如 `# Examples` 的标题，以及代码块高亮\n",
    "- 被注释的对象需要使用 `pub` 对外可见，记住：文档注释是给用户看的，**内部实现细节不应该被暴露出去**\n",
    "\n",
    "咦？文档注释中的例子，为什看上去像是能运行的样子？竟然还是有 `assert_eq` 这种常用于测试目的的宏。 嗯，你的感觉没错，详细内容会在本章后面讲解，容我先卖个关子。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 文档块注释 /** ... */"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "/** `add_two` 将指定值加2\n",
    "\n",
    "\n",
    "```\n",
    "let arg = 5;\n",
    "let answer = my_crate::add_two(arg);\n",
    "\n",
    "assert_eq!(7, answer);\n",
    "```\n",
    "*/\n",
    "pub fn add_two(x: i32) -> i32 {\n",
    "    x + 2\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 查看文档 cargo doc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 运行 `cargo doc` 可以直接生成 `HTML` 文件，放入*target/doc*目录下\n",
    "- 使用 `cargo doc --open` 命令，可以在生成文档后，自动在浏览器中打开网页"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [常用文档标题](https://course.rs/basic/comment.html#常用文档标题)\n",
    "\n",
    "之前我们见到了在文档注释中该如何使用 `markdown`，其中包括 `# Examples` 标题。除了这个标题，还有一些常用的，你可以在项目中酌情使用：\n",
    "\n",
    "- **Panics**：函数可能会出现的异常状况，这样调用函数的人就可以提前规避\n",
    "- **Errors**：描述可能出现的错误及什么情况会导致错误，有助于调用者针对不同的错误采取不同的处理方式\n",
    "- **Safety**：如果函数使用 `unsafe` 代码，那么调用者就需要注意一些使用条件，以确保 `unsafe` 代码块的正常工作\n",
    "\n",
    "话说回来，这些标题更多的是一种惯例，如果你非要用中文标题也没问题，但是最好在团队中保持同样的风格 :)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# [包和模块级别的注释](https://course.rs/basic/comment.html#包和模块级别的注释)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 包增加注释，在 `src/lib.rs` 包根的最上方"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "/*! lib包是world_hello二进制包的依赖包，\n",
    " 里面包含了compute等有用模块 */\n",
    "\n",
    "pub mod compute;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 为该包根的子模块 `src/compute.rs` 添加注释"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "//! 计算一些你口算算不出来的复杂算术题\n",
    "\n",
    "\n",
    "/// `add_one`将指定值加1\n",
    "///"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 文档测试(Doc Test)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Rust 允许我们在文档注释中写单元测试用例！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "/// `add_one` 将指定值加1\n",
    "///\n",
    "/// # Examples\n",
    "///\n",
    "/// ```\n",
    "/// let arg = 5;\n",
    "/// let answer = doc_test::add_one(arg);\n",
    "///\n",
    "/// assert_eq!(6, answer);\n",
    "/// ```\n",
    "pub fn add_one(x: i32) -> i32 {\n",
    "    x + 1\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\n",
       "running 1 test\n",
       ".\n",
       "test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s\n",
       "\n"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd demo && cargo test --doc -q"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 造成 panic 的文档测试"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "/// # Panics\n",
    "///\n",
    "/// The function panics if the second argument is zero.\n",
    "///\n",
    "/// ```rust\n",
    "/// // panics on division by zero\n",
    "/// world_hello::compute::div(10, 0);\n",
    "/// ```\n",
    "pub fn div(a: i32, b: i32) -> i32 {\n",
    "    if b == 0 {\n",
    "        panic!(\"Divide-by-zero error\");\n",
    "    }\n",
    "\n",
    "    a / b\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果想要通过这种测试，可以添加 `should_panic`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "/// # Panics\n",
    "///\n",
    "/// The function panics if the second argument is zero.\n",
    "///\n",
    "/// ```rust,should_panic\n",
    "/// // panics on division by zero\n",
    "/// world_hello::compute::div(10, 0);\n",
    "/// ```\n",
    "pub fn div(a: i32, b: i32) -> i32 {\n",
    "    if b == 0 {\n",
    "        panic!(\"Divide-by-zero error\");\n",
    "    }\n",
    "\n",
    "    a / b\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 保留测试，隐藏文档"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "/// ```\n",
    "/// # // 使用#开头的行会在文档中被隐藏起来，但是依然会在文档测试中运行\n",
    "/// # fn try_main() -> Result<(), String> {\n",
    "/// let res = world_hello::compute::try_div(10, 0)?;\n",
    "/// # Ok(()) // returning from try_main\n",
    "/// # }\n",
    "/// # fn main() {\n",
    "/// #    try_main().unwrap();\n",
    "/// #\n",
    "/// # }\n",
    "/// ```\n",
    "pub fn try_div(a: i32, b: i32) -> Result<i32, String> {\n",
    "    if b == 0 {\n",
    "        Err(String::from(\"Divide-by-zero\"))\n",
    "    } else {\n",
    "        Ok(a / b)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 文档注释中的代码跳转"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 文档注释里的 `[]` 可以创建指向外部项（如标准库）的超链接，方便在 IDE 或生成文档中跳转。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "/// `add_one` 返回一个[`Option`]类型\n",
    "pub fn add_one(x: i32) -> Option<i32> {\n",
    "    Some(x + 1)\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 可以用模块路径（例如 `crate::Type` 或 `std::future::Future`）跳转到自定义代码或其他库的具体项。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "pub mod a {\n",
    "    /// `add_one` 返回一个[`Option`]类型\n",
    "    /// 跳转到[`crate::MySpecialFormatter`]\n",
    "    pub fn add_one(x: i32) -> Option<i32> {\n",
    "        Some(x + 1)\n",
    "    }\n",
    "}\n",
    "\n",
    "pub struct MySpecialFormatter;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 遇到同名项时，用 `struct@Foo`、`fn@Foo` 等标记明确跳转目标类型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "/// 跳转到结构体  [`Foo`](struct@Foo)\n",
    "pub struct Bar;\n",
    "\n",
    "/// 跳转到同名函数 [`Foo`](fn@Foo)\n",
    "pub struct Foo {}\n",
    "\n",
    "/// 跳转到同名宏 [`foo!`]\n",
    "pub fn Foo() {}\n",
    "\n",
    "#[macro_export]\n",
    "macro_rules! foo {\n",
    "  () => {}\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 文档搜索别名"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Rust 文档支持搜索功能，我们可以为自己的类型定义几个别名，以实现更好的搜索展现，当别名命中时，搜索结果会被放在第一位："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "#[doc(alias = \"x\")]\n",
    "#[doc(alias = \"big\")]\n",
    "pub struct BigX;\n",
    "\n",
    "#[doc(alias(\"y\", \"big\"))]\n",
    "pub struct BigY;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 一个综合例子"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- [main.rs](./doc_test/src/main.rs)\n",
    "- [lib.rs](./doc_test/src/lib.rs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "    Creating binary (application) `doc_test` package\n",
       "note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cargo new doc_test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       " Documenting doc_test v0.1.0 (/mnt/d/dev_learn/learnrustbyai_fk/rust_course/02_intro/2.13_注释和文档/doc_test)\n",
       "    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.01s\n",
       "   Generated /mnt/d/dev_learn/learnrustbyai_fk/rust_course/02_intro/2.13_注释和文档/doc_test/target/doc/doc_test/index.html\n"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd doc_test && cargo doc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\n",
       "running 1 test\n",
       "test src/lib.rs - utils::mix (line 33) ... ok\n",
       "\n",
       "test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s\n",
       "\n",
       "   Compiling doc_test v0.1.0 (/mnt/d/dev_learn/learnrustbyai_fk/rust_course/02_intro/2.13_注释和文档/doc_test)\n",
       "    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.28s\n",
       "   Doc-tests doc_test\n"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd doc_test && cargo test --doc"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Rust",
   "language": "rust",
   "name": "rust"
  },
  "language_info": {
   "codemirror_mode": "rust",
   "file_extension": ".rs",
   "mimetype": "text/rust",
   "name": "Rust",
   "pygment_lexer": "rust",
   "version": ""
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
